<?php

declare(strict_types=1);

namespace Vipkwd\SDK\Qrcdr\Dependents;

class Utils
{
    private static $logDebug = !true;
    /**
     * 检测数组是否为索引数组(且从0序开始)
     *
     *
     * @param mixed $value
     */
    static function isIndexList($value): bool
    {
        return is_array($value) && (PHP_VERSION_ID < 80100
            ? !$value || array_keys($value) === range(0, count($value) - 1)
            : \array_is_list($value)
        );
    }
    /**
     * 字符XSS过滤
     *
     * @param string|array $str 待检字符 或 索引数组
     * @param boolean $dpi <false> 除常规过滤外，是否深度(额外使用正则)过滤。默认false仅常规过滤
     * @return string|array
     */
    static function removeXss($str, bool $dpi = false, bool $keepHtmlTag = false)
    {
        if (!is_array($str)) {
            $str = trim($str);
            $keepHtmlTag === false && $str = strip_tags($str);
            $str = htmlspecialchars($str);
            if ($dpi === true) {
                $str = str_replace(array('"', "\\", "'", "/", "..", "../", "./", "//"), '', $str);
                $no = '/%0[0-8bcef]/';
                $str = preg_replace($no, '', $str);

                // 移除 百分号后两位字符
                $no = '/%1[0-9a-f]/';
                $str = preg_replace($no, '', $str);

                // 移除W3C的标准下，XML文件无法识别的字符
                $no = '/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]+/S';
                $str = preg_replace($no, '', $str);
            }
            return $str;
        }
        foreach ($str as $k => $v) {
            $str[$k] = self::removeXss($v, $dpi);
        }
        return $str;
    }

    /**
     * 数据解码(xss)
     * 
     * @param mixed $data
     * @param bool $rxss <true> 是否转义为实体符
     * 
     * @return mixed
     * 
     */
    static function encode($data, $rxss = true)
    {
        if (is_array($data)) {
            foreach ($data as $k => $v) {
                $data[$k] = self::encode($v, $rxss);
            }
            return $data;
        } else {
            $type = strtolower(gettype($data));
            switch ($type) {
                case "boolean":
                case "object":
                case "integer":
                case "double":
                case "null":
                    break;
                case "string":
                    $data = trim($data);
                    $firstChar = substr($data, 0, 1);
                    $lastChar = substr($data, -1);
                    if (($firstChar == '{' && $lastChar == '}') || ($firstChar == '[' && $lastChar == ']')) {
                        return self::encode(json_decode($data, true), $rxss);
                    } else {
                        $data = urldecode($data);
                        $data = trim($rxss ? self::removeXss($data) : $data);
                    }
                    break;
                default:
                    $data = Null;
                    break;
            }
            return $data;
        }
    }

    /**
     * 记录日志
     */
    static function log($data, string $event = 'info', string $logFile = null)
    {
        if (!self::$logDebug)
            return;

        if ($logFile) {
            $logFile = realpath($logFile);
            if (!is_dir(dirname($logFile))) {
                mkdir(dirname($logFile), 0755, true);
            }
        } else {
            $logFile = (realpath(__DIR__ . '/../../../../../')) . '/vk-oauth.log';
        }

        switch (strtolower(gettype($data))) {
            case "boolean":
            case "bool":
                $data = 'Bool::' . ($data === true ? 'true' : 'false');
                break;
            case "null":
                $data = 'Null::null';
                break;
            case "object":
                $data = get_object_vars($data);
                $data = "Object::" . json_encode($data);
                break;
            case "array":
                if (isset($data['expires_time']))
                    $data['expires_time_'] = date('Y-m-d H:i:s', $data['expires_time']);
                if (isset($data['refresh_token_time']))
                    $data['refresh_token_time_'] = date('Y-m-d H:i:s', $data['refresh_token_time']);
                $data = json_encode($data);
                break;
        }
        $backTrace = debug_backtrace();

        $traceList = [];
        foreach ($backTrace as $k => $trace) {
            $traceStr = PHP_EOL;
            $traceStr .= sprintf("    %s(%d) ", $trace['file'], $trace['line']);
            $traceStr .= sprintf(" %s%s%s(...", $trace['class'], $trace['type'], $trace['function']);

            $args = json_encode($trace['args']); //剔除对象嵌套
            $args = json_decode($args, true);
            $args = var_export($args, true);//导出数组结构
            $args = explode("\n", $args);

            foreach ($args as $k => $v) {
                if ($k > 0)
                    $args[$k] = '       ' . $v;
            }
            $args = implode("\n", $args);
            $traceStr .= sprintf("%s)%s\r\n", $args, PHP_EOL);

            $traceList[] = $traceStr;
        }
        $traceStr = '';
        $length = count($traceList) - 1;
        for ($i = 0; $i <= $length; $i++) {
            $traceStr .= ("    " . str_pad(strval($length - $i + 1), 2, ' ', STR_PAD_RIGHT) . ': ' . ltrim($traceList[$i]));
        }

        $data = sprintf("%s[%s][%s] %s\r\n", PHP_EOL, date('Y-m-d H:i:s'), $event, $data);
        file_put_contents($logFile, $data, FILE_APPEND);
        file_put_contents($logFile, $traceStr, FILE_APPEND);
        unset($data, $logFile, $traceStr, $traceList, $backTrace);
    }
}